package cn.kgc;

import cn.kgc.utils.RabbitConnectUtil;
import cn.kgc.websocket.WebSocketServerInitializer;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 聊天服务器的启动类
 *
 * @author YC
 */
public class ChatServer {

    public static void main(String[] args) {
        // 启动聊天服务器
        startChatServer();
        // 初始化消息队列
        initRabbitmq();
    }

    /**
     * 初始化消息队列
     */
    private static void initRabbitmq() {
        Connection connection = null;
        try {
            // 获得连接
            connection = RabbitConnectUtil.getConnection();
            Channel channel = connection.createChannel();
            // 创建交换机    参数：(交换机名,持久化,是否自动删除)
            channel.exchangeDeclare("chatExchange", "direct", true);
            // 创建队列     参数：(队列名,持久化：topic通配符/direct,排他,是否自动删除,队列其他参数)
            channel.queueDeclare("chatQueue", true, false, false, null);
            // 绑定队列和交换机     参数：(队列名,交换机名,路由键)
            channel.queueBind("chatQueue", "chatExchange", "chat");
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 连接不为空时，归还连接
            if (connection != null) {
                RabbitConnectUtil.returnConnection(connection);
            }
        }
    }

    /**
     * 启动聊天服务器
     */
    private static void startChatServer() {
        // 主线程池来接收客户端发送的请求
        NioEventLoopGroup boosGroup = new NioEventLoopGroup();
        // 工作线程池来处理客户端发送的请求
        NioEventLoopGroup workGroup = new NioEventLoopGroup();
        // 创建服务启动对象
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        // 设置主线程池和工作线程池
        serverBootstrap.group(boosGroup, workGroup)
                // 客户端和服务端通信的通道类型（通过通道实现客户端与服务端之间发送信息）
                .channel(NioServerSocketChannel.class)
                //创建处理Http请求的handler
                .childHandler(new WebSocketServerInitializer());
        try {
            // 设置聊天服务的端口号 bind方法是非阻塞的，sync方法会阻塞，以防止绑定端口没执行完成继续往下执行
            ChannelFuture sync = serverBootstrap.bind(4025).sync();
            // 监听关闭事件，阻塞直到监听到关闭事件执行以下逻辑，防止服务端关闭
            sync.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            boosGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
